package com.ls.fw.mvc.springmvc.base;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.hateoas.mvc.ControllerLinkBuilderFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.ls.fw.commons.core.utils.io.FileUtils;
import com.ls.fw.mvc.springmvc.util.BeanValidators;
import com.ls.fw.web.core.servlet.utils.HttpUtils;

/**
 * 
 * 
 * @author lisheng
 * @date 2015年6月27日 下午3:59:42
 * @version V1.0
 */
public abstract class BaseController extends BaseSimpleController{

	protected static final String LIST = "list";
	protected static final String ADD = "add";
	protected static final String EDIT = "edit";
	protected static final String DETAIL = "detail";
	protected static final String UPDATE = "update";
	protected static final String SHOW = "show";
	protected static final String ERROR = "error";
	protected static final String SAVE = "save";
	protected static final String DELETE = "delete";
	protected static final String REMOVE = "remove";
	protected static final String QUERY = "query";
	protected static final String UPLOAD = "upload";
	protected static final String DOWNLOAD = "download";
	
	protected ControllerLinkBuilderFactory linkFactory = new ControllerLinkBuilderFactory();
	/**
	 * 首页相对路径
	 */
	@Value("${fw.view.index}")
	protected String index= "";
	/**
	 * 后台系统域
	 */
	@Value("${fw.view.backendDomain}")
	protected String backendDomain = "";
	/**
	 * 前台系统域
	 */
	@Value("${fw.view.frontDomain}")
	protected String frontDomain = "";
	 
	/**
	 * 前端URL后缀
	 */
	@Value("${fw.view.urlSuffix}")
	protected String urlSuffix = "";
	/**
	 * 验证Bean实例对象
	 */
	@Autowired(required=false)
	protected Validator validator;

	/**
     * 实体类型
     */
//    protected final Class<M> entityClass;

	//方法请求路径的前缀（及控制层的请求路径）
	protected String viewPrefix;

	//方法映射的请求路径
    protected final Map<String,String> methodRequestMapping = new HashMap<String,String>();
    
    protected BaseController() {
//    	this.entityClass = ReflectUtils.findParameterizedType(getClass(), 0);
        this.setViewPrefix(defaultViewPrefix());
        try {
	   		Method[] ms = this.getClass().getMethods();
	   		if(ms!=null){
	   			for (Method method : ms) {
					RequestMapping requestMapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);
			        if (requestMapping != null && requestMapping.value().length > 0) {
			        	methodRequestMapping.put(method.getName(),requestMapping.value()[0]);
			        }
				}
	   		}
		 }catch (Exception e) {
		 }
         this.logger.debug("methodRequestMapping:"+methodRequestMapping.toString());
    }

	/**
	 * 服务端参数有效性验证
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true；严重失败：将错误信息添加到 message 中
	 */
	protected boolean beanValidator(Model model, Object object, Class<?>... groups) {
		try{
			BeanValidators.validateWithException(validator, object, groups);
		}catch(ConstraintViolationException ex){
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(model, list.toArray(new String[]{}));
			return false;
		}
		return true;
	}
	
	/**
	 * 服务端参数有效性验证
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true；严重失败：将错误信息添加到 flash message 中
	 */
	protected boolean beanValidator(RedirectAttributes redirectAttributes, Object object, Class<?>... groups) {
		try{
			BeanValidators.validateWithException(validator, object, groups);
		}catch(ConstraintViolationException ex){
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(redirectAttributes, list.toArray(new String[]{}));
			return false;
		}
		return true;
	}
	  
    /**
     * 设置通用数据
     *
     * @param model
     */
    protected void setCommonData(Model model) {
    }

    /**
     * 当前模块 视图的前缀
     * 默认
     * 1、获取当前类头上的@RequestMapping中的value作为前缀
     * 2、如果没有就使用当前模型小写的简单类名
     */
    protected void setViewPrefix(String viewPrefix) {
//        if (viewPrefix.startsWith("/")) {
//            viewPrefix = viewPrefix.substring(1);
//        }
        this.viewPrefix = viewPrefix;
    }

    protected String getViewPrefix() {
        return viewPrefix;
    }
    
    
//    protected M newModel() {
//        try {
//            return entityClass.newInstance();
//        } catch (Exception e) {
//            throw new IllegalStateException("can not instantiated model : " + this.entityClass, e);
//        }
//    }

    /**
     * 获取视图名称：即prefixViewName + "/" + suffixName
     *
     * @return
     */
    protected String viewName(String suffixName) {
        if (!suffixName.startsWith("/")) {
            suffixName = "/" + suffixName;
        }
        return getViewPrefix() + suffixName;
    }

    /**
     * 共享的验证规则
     * 验证失败返回true
     *
     * @param m
     * @param result
     * @return
     */
    protected <M> boolean hasError(M m, BindingResult result) {
        Assert.notNull(m);
        return result.hasErrors();
    }

    /**
     * @param backURL null 将重定向到默认getViewPrefix()
     * @return
     */
    protected String redirectToUrl(String backURL) {
        if (StringUtils.isBlank(backURL)) {
            backURL = getViewPrefix();
        }
        if (!backURL.startsWith("/") && !backURL.startsWith("http")) {
            backURL = "/" + backURL;
        }
        return "redirect:" + backURL;
    }
    
    
    /**
     * 跳转到指定页面路径（包含"redirect:"表示重定向）
     * @param backURL
     * @return
     */
    protected String toURL(String backURL){
    	 String url = backURL;
    	 if (StringUtils.isBlank(backURL)) {
    		 url = this.getViewPrefix();
         }
    	 return url;
    }
    
    
    /**
     * 跳转到指定页面路径（包含"redirect:"表示重定向）
     * @param methodName
     * @param backURL
     * @return
     */
    protected String toURL(String methodName,String backURL){
	   	 String url = backURL;
	   	 if (StringUtils.isBlank(backURL)) {
	   		 url = this.getViewPrefix();
	   		 if (!StringUtils.isBlank(methodName)) {
		   		 String mapping = this.methodRequestMapping.get(methodName);
		   		 if (!StringUtils.isBlank(mapping)) {
		   			 String p = "";
		   			 if (!StringUtils.isBlank(url)) {
		   				 p = "/";
		   			 }
		   			 url += p + mapping;
		   		 }
	   		 }
	     }
	   	 return url;
   }
 
	/**
     * 下载文件
     * 
     * @author lisheng
     * @date 2015年9月9日 下午10:28:36
     * @version V1.0
     * @param request
     * @param name
     * @param relativeFilePath
     * @return
     * @throws IOException
     */
	protected ResponseEntity<byte[]> download(HttpServletRequest request,
			String name, String relativeFilePath) throws IOException {
		String ctxPath = request.getSession().getServletContext()
				.getRealPath("/")
				+"/"+ relativeFilePath;
		File file = new File(ctxPath);
		return this.download(request, name, file);
	}

    
    /**
     * 下载文件
     * 
     * @author lisheng
     * @date 2015年9月9日 下午10:28:47
     * @version V1.0
     * @param request
     * @param name
     * @param file
     * @return
     * @throws IOException
     */
	protected ResponseEntity<byte[]> download(HttpServletRequest request,
			String name, File file) throws IOException {
		return this.download(request, name, FileUtils.readFileToByteArray(file));
	}
	
	
	/**
	 * 下载文件
	 * 
	 * @author lisheng
	 * @date 2015年10月24日 下午5:11:18
	 * @version V1.0
	 * @param request
	 * @param name
	 * @param is
	 * @return
	 * @throws IOException
	 */
	protected ResponseEntity<byte[]> download(HttpServletRequest request,
			String name, InputStream is) throws IOException {
//		ByteArrayOutputStream os = new ByteArrayOutputStream();
//		IOUtils.copy(is, os);
//		//写入os操作
//		os.flush();
//		//IOUtils.toByteArray(is)
		return this.download(request, name, IOUtils.toByteArray(is));
	}
	
	/**
	 * 下载文件
	 * @author lisheng
	 * @date 2015年9月9日 下午10:31:25
	 * @version V1.0
	 * @param request
	 * @param name
	 * @param file
	 * @return
	 * @throws IOException
	 */
	protected ResponseEntity<byte[]> download(HttpServletRequest request,
			String name, byte[] file) throws IOException {
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//		headers.setContentDispositionFormData("attachment",
//				HttpUtils.encode(request, name));
		String filename =  HttpUtils.encode(request,name);
		StringBuilder builder = new StringBuilder("name=\"");
	    builder.append("attachment").append('\"');
        if (StringUtils.isNotBlank(filename)) {
            builder.append("; filename=\"");
            builder.append(filename).append('\"');
        }
        headers.set(HttpHeaders.CONTENT_DISPOSITION, builder.toString());
		return new ResponseEntity<byte[]>(file,
				headers, HttpStatus.OK);
	}
	
	/**
	 * 下载文件
	 * 
	 * @param is
	 * @param response
	 * @return
	 * @throws IOException
	 * @author ls 2014年9月9日下午10:29:18
	 */
	protected int down(InputStream is, HttpServletResponse response)
			throws IOException {
		return FileCopyUtils.copy(is, response.getOutputStream());
	}
}





